package org.springframework;

import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.bean.User;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;

import java.beans.IntrospectionException;
import java.util.Arrays;
import java.util.Map;

public class BeanWrapperTest {

	Logger log = LoggerFactory.getLogger(BeanWrapperTest.class);

	@Test
	public void testBeanWrapper() {
		//在构造的过程中就会实例化
		BeanWrapperImpl beanWrapper = new BeanWrapperImpl(User.class);

		//通过beanWrapper设置属性
		beanWrapper.setPropertyValue("name", "wangwu");
		beanWrapper.setPropertyValue("age", 18);
		log.info("bean -> {}", beanWrapper.getWrappedInstance());

		// 通过beanWrapper使用map批量设置属性
		Map<String, Object> map = Map.of("name", "zhangsan", "age", 10);
		beanWrapper.setPropertyValues(map);
		log.info("bean -> {}", beanWrapper.getWrappedInstance());

		// 通过beanWrapper使用MutablePropertyValues批量设置属性
		MutablePropertyValues pvs = new MutablePropertyValues();  // 是不是beanDefinition中的内容
		pvs.addPropertyValue("name","lisi");
		pvs.addPropertyValue("age", 20);
		beanWrapper.setPropertyValues(pvs);
		log.info("bean -> {}", beanWrapper.getWrappedInstance());
	}

	@Test
	public void testBatchCreate() throws IntrospectionException, ClassNotFoundException {
		// 1、创建一个beanDefinitionRegistry
		BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
		// 2、创建一个beanDefinitionReader
		BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(registry);
		beanDefinitionReader.loadBeanDefinitions("bean.xml");

		// 3、遍历beanDefinitionRegistry中的beanDefinition
		String[] beanDefinitionNames = registry.getBeanDefinitionNames();
		for (String beanDefinitionName : beanDefinitionNames) {
			log.info("beanDefinitionName -> {}", beanDefinitionName);
			BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
			// 4、对beanDefinition进行包装,进行实例化
			Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());
			BeanWrapper beanWrapper = new BeanWrapperImpl(beanClass);
			// 5、进行属性填充(异常，xml中读取的是统一的"1" "0.1" "aaa"  --> 各自的真实属性类型) 类型转化，全部都是归一化的TypedStringValue
			GenericConversionService service = new GenericConversionService();
			service.addConverter(new Converter<TypedStringValue, String>() {
				@Override
				public @Nullable String convert(TypedStringValue source) {
					return source.getValue();
				}
			});
			service.addConverter(new Converter<TypedStringValue, Integer>() {
				@Override
				public @Nullable Integer convert(TypedStringValue source) {
					return Integer.parseInt(source.getValue());
				}
			});
			beanWrapper.setConversionService(service);
			beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());
			log.info("bean -> {}", beanWrapper.getWrappedInstance());
		}

	}


	@Test
	public void testTypeResolvableType() throws NoSuchFieldException {
		ResolvableType type = ResolvableType.forField(DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects"));
		// 获取类型
		log.info(type.getType().getTypeName());
		// 获取泛型
		log.info(Arrays.toString(type.getGenerics()));
		log.info(Arrays.toString(type.getInterfaces()));
		log.info(Arrays.toString(type.resolveGenerics()));
		// 获取来源
		Class<?> resolve = type.resolve();
		log.info(type.getRawClass().getName());
	}
}
